package cate.game.role.res.worldtree.share;

import cate.common.table.res.worldtree.row.HeroShareBaseRow;
import cate.common.table.res.worldtree.row.HeroShareCostRow;
import cate.common.util.GameResult;
import cate.game.event.hero.HeroLevelChangeEvent;
import cate.game.event.worldtree.HeroShareAddedEvent;
import cate.game.event.worldtree.ShareLevelChangeEvent;
import cate.game.res.MixRes;
import cate.game.res.MixResItem;
import cate.game.role.Role;
import cate.game.role.RoleDependent;
import cate.game.role.bag.hero.Hero;
import cate.game.role.res.worldtree.msg.HeroShareDataResp;
import cate.game.train.hero.msg.HeroBaseBatchUpdateResp;
import cate.game.train.hero.msg.HeroBaseUpdateResp;
import cate.game.train.hero.msg.HeroLockResp;
import com.fasterxml.jackson.annotation.JsonIgnore;
import easy.java.dev.note.NoteClass;
import easy.java.dev.note.NoteField;
import easy.java.practice.errorcode.EcResult;
import org.springframework.data.annotation.Transient;

import java.util.*;

@NoteClass(value = "英雄共享背包 ")
public class HeroShare extends RoleDependent {
    @NoteField(value = "最高英雄唯一id列表")
    public List<String> lst;

    @NoteField(value = "共享等级")
    public int shareLvl;

    @NoteField("历史最高共享等级")
    public int shareLvlMax;

    @NoteField(value = "共享的阶数")
    public int shareGrade;

    @NoteField("历史最高共享星数")
    public int shareStarMax;

    @NoteField("最高英雄等级")
    public int lvlMax;

    @NoteField("最高英雄战力")
    public long heroPowerMax;

    @NoteField(
            value = "英雄共享背包",
            detail = "Map<背包位置, 共享的英雄>")
    public Map<Integer, HeroShareBagBox> heroShareBag;

    @Override
    public void initialize(Role role) {
        super.initialize(role);
        if (lst == null) {
            lst = new ArrayList<>();
        }
        if (shareLvlMax <= shareLvl) {
            shareLvlMax = shareLvl;
        }
        if (heroShareBag == null) {
            heroShareBag = new HashMap<>();
            HeroShareBaseRow base = getBase();
            if (base != null) {
                base.defaultBoxs.forEach(boxIdx -> heroShareBag.put(boxIdx, new HeroShareBagBox(boxIdx)));
            }
        }
        game().pvp.status.updateStarMax(role.getUid(), shareStarMax);
    }

    @JsonIgnore
    public HeroShareBaseRow getBase() {
        return role.getGame().table.worldTree.heroShareBase.get(1);
    }

    /**
     * 添加共享
     */
    public GameResult<Void> addHeroShare(String uid, int pos) {
        GameResult<Void> rr = new GameResult<>();
        HeroShareBaseRow row = getBase();
        if (row == null) {
            return rr.fail("英雄不足共享等级无法触发！");
        }
        // 英雄数量不足啊
        if (lst == null || lst.size() < row.limitHeroCnt) {
            return rr.fail("英雄不足共享等级无法触发！");
        }
        Hero hero = role.getBag().hero.getItem(uid);
        if (hero == null) {
            return rr.fail("英雄不存在！");
        }
        // 有共享等级  已在共享中
        if (hero.shareLevel > 0) {
            return rr.fail("英雄已在共享中！");
        }
        if (!heroShareBag.containsKey(pos)) {
            return rr.fail("位置未解锁！");
        }
        HeroShareBagBox box = heroShareBag.get(pos);
        if (box == null) {
            box = new HeroShareBagBox(pos);
        }
        if (box.pos == pos && box.isBoxEmpty() && !box.isBoxColding()) {
            box.addHero(uid);
            hero.setShareLevel(role, this.shareLvl, this.shareGrade);
            role.sendNow(new HeroLockResp(hero.lock));
            return rr.success();
        }

        publishEvent(role, new HeroShareAddedEvent(role));

        return rr.fail("未添加成功！");
    }

    public boolean heroInTree(String heroUid) {
        return getHeroBox(heroUid) != null;
    }

    private HeroShareBagBox getHeroBox(String heroUid) {
        return heroShareBag.values().stream().filter(e -> e != null && heroUid.equals(e.heroUid)).findAny().orElse(null);
    }

    /**
     * 移除共享
     */
    public GameResult<Integer> delHeroShare(String heroUid) {
        GameResult<Integer> rr = new GameResult<>();
        HeroShareBagBox box = getHeroBox(heroUid);
        if (box == null) {
            return rr.fail("该英雄不在世界树中！");
        }
        if (!box.isBoxEmpty()) {
            Hero hero = role.getBag().hero.getItem(box.heroUid);
            if (hero == null) {
                return rr.fail("英雄不存在！");
            }
            publishEvent(role, new HeroLevelChangeEvent(role, hero, hero.level));
            hero.setShareLevel(role, 0, 0);
            role.sendNow(new HeroLockResp(hero.lock));
            box.cleanBox();
            long now = System.currentTimeMillis();
            HeroShareCostRow bcCostRow = role.getGame().table.worldTree.firstGradeCost.getRow(box.pos);
            now = bcCostRow == null ? now : now + bcCostRow.cleanCD;
            box.addCD(now);
            rr.data = box.pos;
            return rr.success();
        }
        return rr.fail("取消共享失败！");
    }

    /**
     * 移除共享
     */
    public GameResult<Hero> delHeroShare(int pos) {
        GameResult<Hero> rr = new GameResult<>();
        if (!heroShareBag.containsKey(pos)) {
            return rr.fail("格子不存在！");
        }
        // 看看包里是不是有
        HeroShareBagBox box = heroShareBag.get(pos);
        if (box == null) {
            return rr.fail("共享格子错误！");
        }
        if (!box.isBoxEmpty()) {
            Hero hero = role.getBag().hero.getItem(box.heroUid);
            if (hero == null) {
                return rr.fail("英雄不存在！");
            }
            publishEvent(role, new HeroLevelChangeEvent(role, hero, hero.level));
            hero.setShareLevel(role, 0, 0);
            role.sendNow(new HeroLockResp(hero.lock));
            box.cleanBox();
            long now = System.currentTimeMillis();
            HeroShareCostRow bcCostRow = role.getGame().table.worldTree.firstGradeCost.getRow(pos);
            now = bcCostRow == null ? now : now + bcCostRow.cleanCD;
            box.addCD(now);
            rr.data = hero;
            return rr.success();
        }
        return rr.fail("取消共享失败！");
    }

    /**
     * 解锁
     */
    public GameResult<Void> unLuckBox(int untype, int pos) {
        GameResult<Void> rr = new GameResult<>();
        HeroShareCostRow cost = role.getGame().table.worldTree.firstGradeCost.getRow(pos);
        if (cost == null) {
            return rr.fail("位置错误！");
        }
        if (heroShareBag.containsKey(pos)) {
            return rr.fail("位置已解锁！");
        }
        String costStr = untype == 1 ? cost.unlockCost1 : cost.unlockCost2;
        // 看看是否有这个背包格子
        MixRes unlockConsume = new MixRes(costStr);
        GameResult<MixResItem> unluckRes = unlockConsume.copy().consume(role, null);
        if (!unluckRes.ok()) {
            role.getGame().notice.tipResItem(role, unluckRes.data);
            return rr.fail(unluckRes);
        }
        heroShareBag.put(pos, new HeroShareBagBox(pos));
        role.getHistory().action.worldTreeBoxNum();
        return rr;
    }

    /**
     * 清cd
     */
    public GameResult<Void> cleanBoxCD(int cleanType, int pos) {
        GameResult<Void> rr = new GameResult<>();
        HeroShareCostRow cost = role.getGame().table.worldTree.firstGradeCost.getRow(pos);
        if (cost == null) {
            return rr.fail("位置错误！");
        }
        // 看看是否有这英雄共享格子
        if (!heroShareBag.containsKey(pos)) {
            return rr.fail("错误的共享背包位置！");
        }
        HeroShareBagBox box = heroShareBag.get(pos);
        if (box == null) {
            return rr.fail("要清除的位置错误！");
        }
        if (!box.isBoxColding()) {
            return rr.fail("位置不在cd中！");
        }
        String costStr = cleanType == 1 ? cost.cleanCDCost1 : cost.cleanCDCost2;
        MixRes consume = new MixRes(costStr);
        EcResult<MixResItem> consumeRes = consume.consume(role, null);
        if (!consumeRes.ok()) {
            role.getGame().notice.tipResItem(role, consumeRes.data);
            return rr.fail(consumeRes);
        }
        box.cleanBox();
        return rr;
    }

    @Transient
    @JsonIgnore
    private boolean shutup;
    @Transient
    @JsonIgnore
    private long shutupTime;

    public void shutup() {
        shutup = true;
        shutupTime = System.currentTimeMillis() + 1000;
    }

    public void openYourMouthBaby() {
        shutup = false;
        shutupTime = 0;
        onHeroLvlChange(true);
    }

    private boolean shutupNow() {
        return shutup || System.currentTimeMillis() < shutupTime;
    }

    /**
     * 升阶和升级时调用这个
     */
    public void onHeroLvlChange(boolean isSend) {
        if (shutupNow()) {
            return;
        }
        boolean change;
        synchronized (this) {
            int oldlvl = shareLvl;
            // 重新检测前的top5英雄唯一id列表
            String oldHeros = lst == null ? "" : lst.toString();
            int oldGrade = shareGrade;
            checkTopHeros();
            shareLvlFresh();
            // 检测之后新的top5英雄唯一id列表
            String dstLst = lst == null ? "" : lst.toString();
            change = oldlvl != shareLvl || !oldHeros.equals(dstLst) || oldGrade != shareGrade;
            // 证明共享等级变化了 或者英雄变化了
            if (change) {
                batchUpdate2ClientAll();
            }
        }
        if (change) {
            role.sendNow(new HeroShareDataResp(this));
            publishEvent(role, new ShareLevelChangeEvent(role, shareLvl));
        }
        if (isSend) {
            role.getBase().updatePower();
        }
    }

    private void checkTopHeros() {
        HeroShareBaseRow row = getBase();
        if (row == null) {
            return ;
        }
        int setCnt = row.limitHeroCnt;
        lst = new ArrayList<>();
        List<Hero> tmpLst = new ArrayList<>(role.getBag().hero.getList());
        sortHeros(tmpLst);
        // 英雄总数不足
        if (tmpLst.size() < setCnt) {
            tmpLst.forEach(
                    h -> {
                        h.setShareLevel(role, 0, 0); // 前5英雄不需要共享等级
                        lst.add(h.uid);
                        heroPowerMax = Math.max(h.getPower(role.getGame().fight.getPlayBuildContext()), heroPowerMax);
                    });
            shareLvl = 0;
            shareGrade = 0;
            shareStarMax = Math.max(shareStarMax, tmpLst.stream().mapToInt(h -> h.getTpl(role.getGame()).star).sum());
            game().pvp.status.updateStarMax(role.getUid(), shareStarMax);
        } else {
            int totalStar = 0;
            for (int i = 0; i < setCnt; i++) {
                // 前5英雄不需要共享等级
                tmpLst.get(i).setShareLevel(role, 0, 0);
                lst.add(tmpLst.get(i).uid);
                totalStar += tmpLst.get(i).getTpl(role.getGame()).star;
                heroPowerMax = Math.max(tmpLst.get(i).getPower(role.getGame().fight.getPlayBuildContext()), heroPowerMax);
            }
            shareStarMax = Math.max(shareStarMax, totalStar);
            game().pvp.status.updateStarMax(role.getUid(), shareStarMax);
            if (tmpLst.size() >= setCnt) {
                shareLvl = tmpLst.get(setCnt - 1).level;
                shareGrade = tmpLst.get(setCnt - 1).grade;
                updateHighestShareLevel(shareLvl);
            } else {
                shareLvl = 0;
                shareGrade = 0;
                logger.error("共享英雄排序出错了");
            }

            heroShareBag.values().forEach(
                    box -> {
                        if (lst.contains(box.heroUid)) { // 下边添加共享的变成前五了，那几把他取出来
                            Hero hero = update2ClientByOnlyId(box.heroUid);
                            if (hero != null) {
                                hero.lock.noticeUpdate(role);
                            }
                            box.cleanBox();
                        }
                    });
        }
    }

    public void shareLvlFresh() {
        heroShareBag.values().forEach(
                box -> {
                    Hero hp = role.getBag().hero.getItem(box.heroUid);
                    if (hp != null) {
                        hp.setShareLevel(role, this.shareLvl, this.shareGrade);
                    }
                });
    }

    public void sortHeros(List<Hero> lst) {
        lst.sort(Comparator.comparing((Hero hp) -> -hp.level)
                .thenComparing(hp -> -hp.getTpl(role.getGame()).star)
                .thenComparing(hp -> -hp.getPower(role.getGame().fight.getPlayBuildContext()))
                .thenComparing(hp -> -hp.tid));
        if (!lst.isEmpty()) {
            lvlMax = Math.max(lvlMax, lst.get(0).level);
        }
    }

    /**
     * 登录时重新检测共享相关信息
     */
    @Override
    public void onEnter() {
        onHeroLvlChange(false);
    }

    public void noticeUpdate() {
        role.send(new HeroShareDataResp(this));
    }

    /**
     * 给客户端推送 改变的共享英雄信息
     */
    public Hero update2ClientByOnlyId(String uid) {
        Hero hero = role.getBag().hero.getItem(uid);
        if (hero != null) {
            HeroBaseUpdateResp.send(role, hero);
        }
        return hero;
    }

    public void batchUpdate2ClientAll(){
        List<Hero> heros = new ArrayList<>();
        for (HeroShareBagBox value : heroShareBag.values()) {
            if (!value.isBoxEmpty()) {
                Hero hero = role.getBag().hero.getItem(value.heroUid);
                if (hero != null) {
                    heros.add(hero);
                }
            }
        }
        if (!heros.isEmpty()) {
            role.sendNow(new HeroBaseBatchUpdateResp(heros));
        }
    }

    /**
     * 更新最高共享等级
     *
     * @param level level
     */
    public void updateHighestShareLevel(int level) {
        if (level > shareLvlMax) {
            shareLvlMax = level;
        }
    }
}
